package rule;


import org.omg.CORBA.ORB;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 执行器构建规则服务
 * </P>
 *
 * @author dingwen
 * @date 2021.09.09 10:39
 */
public class RuleService<R, T> {
    /**
     * 规则对象集合
     */
    private final Map<Integer, List<AbstractBaseRule<R, T>>> ruleMap = new HashMap<>();

    /**
     * AND 规则列表
     */
    private final List<AbstractBaseRule<R, T>> ruleAndList = new ArrayList<>();
    /**
     * or 规则列表
     */
    private final List<AbstractBaseRule<R, T>> ruleOrList = new ArrayList<>();

    /**
     * 类型:
     * 1: AND
     * 0: OR
     */
    private int type = 1;

    /**
     * 和
     */
    private static final int AND = 1;
    /**
     * 或
     */
    private static final int OR = 0;

    private RuleService() {
    }

    public static <R, T> RuleService<R, T> getInstance() {
        return new RuleService<>();
    }


    /**
     * 和
     *
     * @return {@link RuleService<>}
     */
    public final RuleService<R, T> and() {
        type = AND;
        return this;
    }


    /**
     * 或
     *
     * @return {@link RuleService<>}
     */
    public final RuleService<R, T> or() {
        type = OR;
        return this;
    }

    /**
     * 构建器
     *
     * @param rule 规则
     * @return {@link RuleService<>}
     */
    public RuleService<R, T> builder(AbstractBaseRule<R, T> rule) {
        if (type == AND) {
            ruleAndList.add(rule);
        } else {
            ruleOrList.add(rule);
        }
        return this;
    }

    /**
     * 构建
     *
     * @return {@link RuleService<>}
     */
    public RuleService<R, T> build() {
        if (type == AND) {
            ruleMap.put(AND, ruleAndList);
        } else {
            ruleMap.put(OR, ruleOrList);
        }
        return this;
    }


    /**
     * 和
     *
     * @param ruleDto  规则dto
     * @param ruleList 规则列表
     * @return {@link Boolean}
     */
    private Boolean and(RuleDto<T> ruleDto, List<AbstractBaseRule<R, T>> ruleList) {
        return ruleList.stream().parallel().allMatch(rtAbstractBaseRule -> rtAbstractBaseRule.executeBoolean(ruleDto));
    }


    /**
     * 或
     *
     * @param ruleDto  规则dto
     * @param ruleList 规则列表
     * @return {@link Boolean}
     */
    private Boolean or(RuleDto<T> ruleDto, List<AbstractBaseRule<R, T>> ruleList) {
        return ruleList.stream().parallel().anyMatch(rtAbstractBaseRule -> rtAbstractBaseRule.executeBoolean(ruleDto));
    }


    /**
     * 执行
     *
     * @param ruleDto 规则dto
     * @return {@link Boolean}
     */
    public Boolean execute(RuleDto<T> ruleDto) {
        boolean result = false;
        if (ruleMap.containsKey(AND) && !ruleMap.containsKey(OR)) {
            result = and(ruleDto, ruleMap.get(AND));
        } else if (!ruleMap.containsKey(AND) && ruleMap.containsKey(OR)) {
            result = or(ruleDto, ruleMap.get(OR));
        } else if (ruleMap.containsKey(AND) && ruleMap.containsKey(OR)) {
            if (type == AND) {
                result = and(ruleDto, ruleMap.get(AND)) && or(ruleDto, ruleMap.get(AND));
            } else {
                result = and(ruleDto, ruleMap.get(OR)) || or(ruleDto, ruleMap.get(OR));
            }
        } else {
            return false;
        }
        ruleMap.clear();
        return result;
    }


    /**
     * 执行
     *
     * @param ruleDto 规则dto
     * @param rule    规则
     * @return {@link R}
     */
    public R execute(RuleDto<T> ruleDto, AbstractBaseRule<R, T> rule) {
        return rule.executeObject(ruleDto);
    }

    /**
     * 执行
     * 没有返回值
     *
     * @param ruleDto 规则dto
     * @param rule    规则
     */
    public void executeVoid(RuleDto<T> ruleDto, AbstractBaseRule<R, T> rule) {
        rule.executeVoid(ruleDto);
    }


}
